package com.xinzhitong.www.utils;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.xinzhitong.www.enumeration.GoodType;
import com.xinzhitong.www.pojo.Trade;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Objects;
import java.util.Properties;

/**
 * 支付工具类
 *
 * @author 徐鑫
 */
@Service
@Transactional
public class PayUtil {
    // 商户appId
    private static String appId;
    // 私钥 pkcs8格式的
    private static String rsaPrivateKey;
    // 服务器异步通知页面路径 需http://或者https://格式的完整路径，不能加?id=123这类自定义参数，必须外网可以正常访问
    private static String notifyUrl;
    // 页面跳转同步通知页面路径 需http://或者https://格式的完整路径，不能加?id=123这类自定义参数，必须外网可以正常访问 商户可以自定义同步跳转地址
    private static String returnUrl;
    // 请求网关地址
    private static String url;
    // 编码
    private static String charset;
    // 返回格式
    private static String format;
    // 支付宝公钥
    private static String alipayPublicKey;
    // 日志记录目录
    private static String logPath;
    // RSA2
    private static String signType;
    //盐
    private static String salt;

    /**
     * 获取对应商品的支付链接参数
     *
     * @param username    用户名
     * @param goodId      商品Id
     * @param goodType    商品类型
     * @param totalAmount 总价
     * @param subject     标题
     * @return 表单
     */
    public static synchronized String getUrlParams(
            String username,
            Integer goodId,
            GoodType goodType,
            Double totalAmount,
            String subject) {
        flash();//刷新参数
        String outTradeNo = createOutTradeNo(username, goodId, goodType);//创建商品订单号
        AlipayClient alipayClient = new DefaultAlipayClient(
                url,
                appId,
                rsaPrivateKey,
                format,
                charset,
                alipayPublicKey,
                signType); //获得初始化的AlipayClient
        AlipayTradeAppPayRequest alipayRequest = new AlipayTradeAppPayRequest();//创建API对应的request
        alipayRequest.setReturnUrl(null);
        alipayRequest.setNotifyUrl(notifyUrl);//在公共参数中设置回跳和通知地址
        alipayRequest.setBizContent("{" +
                " \"out_trade_no\":\"" + outTradeNo + "\"," +
                " \"total_amount\":\"" + totalAmount + "\"," +
                " \"subject\":\"" + subject + "\"," +
                " \"product_code\":\"QUICK_MSECURITY_PAY\"" +
                " }");//填充业务参数
        String params = "";
        try {
            params = alipayClient.sdkExecute(alipayRequest).getBody(); //调用SDK生成表单
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        System.out.println(params);
        return params;
    }

    /**
     * 使用商家订单号执行退款
     *
     * @param outTradeNo   商户订单号
     * @param refundAmount 退款金额
     * @return 是否退款成功
     */
    public static synchronized boolean refund(String outTradeNo, Double refundAmount) {
        flash();
        AlipayClient alipayClient = new DefaultAlipayClient(
                url,
                appId,
                rsaPrivateKey,
                "json",
                "UTF-8",
                alipayPublicKey,
                "RSA2");
        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
        request.setBizContent("{" +
                "\"out_trade_no\":\"" + outTradeNo + "\"," +
                "\"refund_amount\":" + refundAmount + "," +
                "\"refund_reason\":\"正常退款\"," +
                "\"operator_id\":\"OP001\"," +
                "\"store_id\":\"NJ_S_001\"," +
                "\"terminal_id\":\"NJ_T_001\"" +
                "  }");
        AlipayTradeRefundResponse response;
        try {
            response = alipayClient.execute(request);
            if (response.isSuccess()) {
                System.out.println("调用成功");
                return true;
            } else {
                System.out.println("调用失败");
                return false;
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 刷新支付工具的参数
     */
    private static void flash() {
        Properties properties = new Properties();
        // 使用InPutStream流读取properties文件
        try {
            BufferedReader bufferedReader =
                    new BufferedReader(
                            new InputStreamReader(
                                    Objects.requireNonNull(Class.forName("com.xinzhitong.www.utils.PayUtil")
                                            .getClassLoader()
                                            .getResourceAsStream("pay.properties"))));
            properties.load(bufferedReader);
            Class c = Class.forName("com.xinzhitong.www.utils.PayUtil");
            for (Field field : c.getDeclaredFields()) {
                //设置为字段可通过反射访问值
                field.setAccessible(true);
                try {
                    field.set(c, properties.getProperty(field.getName()));
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        } catch (ClassNotFoundException | IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 生成唯一的商户订单号
     *
     * @param username 登录id
     * @param goodId   商品id
     * @return 商户订单号
     */
    public static String createOutTradeNo(String username, Integer goodId, GoodType goodType) {
        //隐藏用户名
        return new SimpleDateFormat("yyyy-MM-dd-hh-mm-ss").format(new Date())
                + '-' + SecretUtil.hide(username, getSalt())
                + '-' + goodId + '-' + goodType;
    }

    /**
     * 从订单号中获取订单业务信息
     *
     * @param OTN 商户订单号
     * @return 订单信息
     */
    public static Trade getTradeFromOTN(String OTN) {
        String[] tmp = OTN.split("-");
        return new Trade(
                SecretUtil.expose(tmp[tmp.length - 3], salt),
                Integer.valueOf(tmp[tmp.length - 2]),
                GoodType.valueOf(tmp[tmp.length - 1]),
                OTN,
                null
        );
    }

    public static String getAppId() {
        flash();
        return appId;
    }

    public static void setAppId(String appId) {
        flash();
        PayUtil.appId = appId;
    }

    public static String getRsaPrivateKey() {
        flash();
        return rsaPrivateKey;
    }

    public static void setRsaPrivateKey(String rsaPrivateKey) {
        flash();
        PayUtil.rsaPrivateKey = rsaPrivateKey;
    }

    public static String getNotifyUrl() {
        flash();
        return notifyUrl;
    }

    public static void setNotifyUrl(String notifyUrl) {
        flash();
        PayUtil.notifyUrl = notifyUrl;
    }

    public static String getReturnUrl() {
        flash();
        return returnUrl;
    }

    public static void setReturnUrl(String returnUrl) {
        flash();
        PayUtil.returnUrl = returnUrl;
    }

    public static String getUrl() {
        flash();
        return url;
    }

    public static void setUrl(String url) {
        flash();
        PayUtil.url = url;
    }

    public static String getCharset() {
        flash();
        return charset;
    }

    public static void setCharset(String charset) {
        flash();
        PayUtil.charset = charset;
    }

    public static String getFormat() {
        flash();
        return format;
    }

    public static void setFormat(String format) {
        flash();
        PayUtil.format = format;
    }

    public static String getAlipayPublicKey() {
        flash();
        return alipayPublicKey;
    }

    public static void setAlipayPublicKey(String alipayPublicKey) {
        flash();
        PayUtil.alipayPublicKey = alipayPublicKey;
    }

    public static String getLogPath() {
        flash();
        return logPath;
    }

    public static void setLogPath(String logPath) {
        flash();
        PayUtil.logPath = logPath;
    }

    public static String getSignType() {
        flash();
        return signType;
    }

    public static void setSignType(String signType) {
        flash();
        PayUtil.signType = signType;
    }

    public static void setSalt(String salt) {
        flash();
        PayUtil.salt = salt;
    }

    public static String getSalt() {
        flash();
        return salt;
    }
}
